/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package gestionedt.planning;

import gestionedt.controllers.CreneauJpaController;
import gestionedt.controllers.EnseignantJpaController;
import gestionedt.controllers.GroupeJpaController;
import gestionedt.controllers.PoolJpaController;
import gestionedt.controllers.PrestationJpaController;
import gestionedt.models.Creneau;
import gestionedt.models.Enseignant;
import gestionedt.models.Groupe;
import gestionedt.models.Pool;
import gestionedt.models.Prestation;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionForward;

/**
 * 
 */
public class GererPlanningAction extends org.apache.struts.actions.DispatchAction {


    /**
     * Affiche la page du planning complète (sélection entités, emploi
     * du temps correspondant et liste des prestations non casées).
     * @param mapping The ActionMapping used to select this instance.
     * @param form The optional ActionForm bean for this request.
     * @param request The HTTP Request we are processing.
     * @param response The HTTP Response we are processing.
     * @throws java.lang.Exception
     * @return
     */
    public ActionForward afficher(ActionMapping mapping, ActionForm form,
            HttpServletRequest request, HttpServletResponse response)
            throws Exception {

        PlanningForm planForm = (PlanningForm) form;
        SelectionForm selForm = (SelectionForm) request
                                                  .getSession()
                                                    .getAttribute("SelectionForm");

        this.remplirPlanningFormCommun(planForm, selForm);
        this.remplirPlanningFormSpe(planForm, selForm);

        return mapping.findForward("planning");
    }

    /**
     * Répond à une requête AJAX qui va utiliser la réponse produite pour mettre
     * à jour uniquement la partie emploi du temps de la page principale
     * (fournit aussi quelques éventuels messages d'information).
     * @param mapping The ActionMapping used to select this instance.
     * @param form The optional ActionForm bean for this request.
     * @param request The HTTP Request we are processing.
     * @param response The HTTP Response we are processing.
     * @throws java.lang.Exception
     * @return
     */
    public ActionForward mettreAJourEDT(ActionMapping mapping, ActionForm form,
            HttpServletRequest request, HttpServletResponse response)
            throws Exception {

        PlanningForm planForm = (PlanningForm) form;
        SelectionForm selForm = (SelectionForm) request
                                                  .getSession()
                                                    .getAttribute("SelectionForm");

        this.remplirPlanningFormCommun(planForm, selForm);

        return mapping.findForward("majedt");
    }

    /**
     * Remplissage du PlanningForm (intermédiaire entre le contrôleur et la vue)
     * commun entre les deux actions "afficher" et "mettreAJourEDT".
     * @param planForm
     * @param selForm
     */
    private void remplirPlanningFormCommun(PlanningForm planForm, SelectionForm selForm) {

        GroupeJpaController ctGrp = new GroupeJpaController();
        // récupération de l'ensemble des groupes d'étudiants
        planForm.setGroupes(ctGrp.getList());

        EnseignantJpaController ctEns = new EnseignantJpaController();
        // récupération de l'ensemble des enseignants
        planForm.setEnseignants(ctEns.getList());

        if(selForm != null) {
            int nbEntitesSel = selForm.getIdsGrpSelectionnes().length
                    + selForm.getIdsEnsSelectionnes().length;
            if(nbEntitesSel > 0) {
                // si au moins une entité (grp ou ens) est sélectionnée :

                // récupération des groupes sélectionnés pour apparaître sur l'EDT
                int[] idsGrpSel = selForm.getIdsIntGrpSelectionnes();
                planForm.setGroupesSel(ctGrp.findGroupesByIds(idsGrpSel));
                // récupération des enseignants sélectionnés pour apparaître sur l'EDT
                int[] idsEnsSel = selForm.getIdsIntEnsSelectionnes();
                planForm.setEnseignantsSel(ctEns.findEnseignantsByIds(idsEnsSel));

                // récupération des prestations qui doivent apparaître sur l'EDT
                PrestationJpaController ctPrest = new PrestationJpaController();
                List<Prestation> prestations = ctPrest.findPrestationsSurEDT(idsGrpSel, idsEnsSel);
                planForm.setPrestationCasees(prestations);
                // remplissage de l'objet EDT
                PlanningForm.EDT edt = planForm.new EDT();
                int i = 0;
                for(Groupe g : planForm.getGroupesSel()) {
                    for(Prestation p : prestations) {
                        // si le groupe courant suit la prestation courante :
                        if(p.getGroupes().contains(g)) {
                            int numCreneau = p.getCreneau().getNumero();
                            PlanningForm.EDT.CaseCreneau c = edt.getCase(numCreneau);
                            c.getSousCases().get(i).setPrestation(p);
                        }
                    }
                    i++;
                }
                for(Enseignant e : planForm.getEnseignantsSel()) {
                    for(Prestation p : prestations) {
                        // si l'enseignant courant assure la prestation courante :
                        if(p.getEnseignant().equals(e)) {
                            int numCreneau = p.getCreneau().getNumero();
                            PlanningForm.EDT.CaseCreneau c = edt.getCase(numCreneau);
                            c.getSousCases().get(i).setPrestation(p);
                        }
                    }
                    i++;
                }
                // une fois que l'objet EDT est rempli, il est passé à l'ActionForm idoine
                planForm.setPlanning(edt);
                // et l'on fussionne les sous-cases qui le permettent
                edt.fusionnerSousCases();
            }
        }
    }

    /**
     * Remplissage du PlanningForm (intermédiaire entre le contrôleur et la vue)
     * spécifique à l'action "afficher".
     * @param planForm
     * @param selForm
     */
    private void remplirPlanningFormSpe(PlanningForm planForm, SelectionForm selForm) {

        if(selForm != null) {
            int nbEntitesSel = selForm.getIdsGrpSelectionnes().length
                    + selForm.getIdsEnsSelectionnes().length;
            if(nbEntitesSel > 0) {
                // si au moins une entité (grp ou ens) est sélectionnée :

                // récupération des identifiants des entités (groupes
                // ou enseignants qui ont été sélectionnées
                int[] idsGrpSel = selForm.getIdsIntGrpSelectionnes();
                int[] idsEnsSel = selForm.getIdsIntEnsSelectionnes();

                // récupération des prestations qui pourraient apparaître
                // sur l'EDT, mais ne sont pas encore placées
                PrestationJpaController ctPrest = new PrestationJpaController();
                List<Prestation> prestations = ctPrest.findPrestationsNonCasees(idsGrpSel, idsEnsSel);
                planForm.setPrestationsNonCasees(prestations);
            }
        }
    }

    /**
     * 
     * @param mapping The ActionMapping used to select this instance.
     * @param form The optional ActionForm bean for this request.
     * @param request The HTTP Request we are processing.
     * @param response The HTTP Response we are processing.
     * @throws java.lang.Exception
     * @return
     */
    public ActionForward placerPrestation(ActionMapping mapping, ActionForm form,
            HttpServletRequest request, HttpServletResponse response)
            throws Exception {

        PlanningForm planForm = (PlanningForm) form;

        // récupération de la prestation
        PrestationJpaController ctPrest = new PrestationJpaController();
        Prestation prest = ctPrest.findPrestation(planForm.getIdPrestation());
        // récupération du créneau
        CreneauJpaController ctCreneau = new CreneauJpaController();
        Creneau creneau = ctCreneau.findCreneau(planForm.getNumCreneau());

        List<String> msg = verifierAucunConflit(prest, creneau);

        if(msg.size() > 0) { // s'il y a des conflits, la prestation ne pourra pas être placée
            planForm.setTypeMessage(PlanningForm.TypeMessage.ERREUR);
            planForm.setTitreMessages("Placement impossible");
            planForm.setMessages(msg);
        }
        else { // pas de conflit => la prestation est placée dans le créneau
            prest.setCreneau(creneau);
            ctPrest.edit(prest);
            
            planForm.setTypeMessage(PlanningForm.TypeMessage.SUCCES);
            planForm.setTitreMessages("Placement effectué");
            msg.add("La prestation dont l'id est " + prest.getId() +
                    " et dont l'enseignant est " + prest.getEnseignant() +
                    " a bien été placée le "+ creneau +".");
            planForm.setMessages(msg);
        }
        return this.mettreAJourEDT(mapping, form, request, response);
    }

    /**
     *
     * @param mapping The ActionMapping used to select this instance.
     * @param form The optional ActionForm bean for this request.
     * @param request The HTTP Request we are processing.
     * @param response The HTTP Response we are processing.
     * @throws java.lang.Exception
     * @return
     */
    public ActionForward remplacerPrestation(ActionMapping mapping, ActionForm form,
            HttpServletRequest request, HttpServletResponse response)
            throws Exception {

        PlanningForm planForm = (PlanningForm) form;

        // récupération des prestations
        PrestationJpaController ctPrest = new PrestationJpaController();
        Prestation prestAPlacer = ctPrest.findPrestation(planForm.getIdPrestation());
        Prestation prestARemplacer = ctPrest.findPrestation(planForm.getIdPrestARemplacer());
        // récupération du créneau
        Creneau creneau = prestARemplacer.getCreneau();

        // Avant de vérifier l'absence de conflit,
        // il faut enlever de l'EDT la prestation à remplacer :
        prestARemplacer.setCreneau(null);
        ctPrest.edit(prestARemplacer);

        List<String> msg = verifierAucunConflit(prestAPlacer, creneau);

        if(msg.size() > 0) { // s'il y a des conflits, la prestation ne pourra pas être remplacée
            // transaction annulée (la prestation à remplacer à remise sur l'EDT)
            prestARemplacer.setCreneau(creneau);
            ctPrest.edit(prestARemplacer);

            planForm.setTypeMessage(PlanningForm.TypeMessage.ERREUR);
            planForm.setTitreMessages("Placement impossible");
            planForm.setMessages(msg);
        }
        else { // pas de conflit => la prestation est remplacée
            prestAPlacer.setCreneau(creneau);
            ctPrest.edit(prestAPlacer);

            planForm.setTypeMessage(PlanningForm.TypeMessage.SUCCES);
            planForm.setTitreMessages("Remplacement effectué");
            msg.add("La prestation dont l'id est " + prestARemplacer.getId() +
                " et dont l'enseignant est " + prestARemplacer.getEnseignant() +
                " a bien été retirée de l'emploi du temps.");
            msg.add("La prestation dont l'id est " + prestAPlacer.getId() +
                    " et dont l'enseignant est " + prestAPlacer.getEnseignant() +
                    " a bien été placée le "+ prestAPlacer.getCreneau() + ".");
            planForm.setMessages(msg);
        }
        return this.mettreAJourEDT(mapping, form, request, response);
    }

    /**
     * 
     * @param mapping The ActionMapping used to select this instance.
     * @param form The optional ActionForm bean for this request.
     * @param request The HTTP Request we are processing.
     * @param response The HTTP Response we are processing.
     * @throws java.lang.Exception
     * @return
     */
    public ActionForward enleverPrestation(ActionMapping mapping, ActionForm form,
            HttpServletRequest request, HttpServletResponse response)
            throws Exception {

        PlanningForm planForm = (PlanningForm) form;

        PrestationJpaController ctPrest = new PrestationJpaController();
        Prestation prest = ctPrest.findPrestation(planForm.getIdPrestation());
        prest.setCreneau(null);
        ctPrest.edit(prest);

        planForm.setTypeMessage(PlanningForm.TypeMessage.SUCCES);
        planForm.setTitreMessages("Prestation retirée");
        List<String> msg = new ArrayList<String>(1);
        msg.add("La prestation dont l'id est " + prest.getId() +
                " et dont l'enseignant est " + prest.getEnseignant() +
                " a bien été retirée de l'emploi du temps.");
        planForm.setMessages(msg);

        return this.mettreAJourEDT(mapping, form, request, response);
    }

    /**
     * Effectue les vérifications nécessaires pour s'assurer qu'il n'y a
     * pas de conflit lorsque la prestation est placée dans le créneau.
     * @param prest prestation à placer
     * @param creneau créneau dans lequel on veut placer la prestation
     * @return liste des conflits
     */
    private List<String> verifierAucunConflit(Prestation prest, Creneau creneau) {
        // vérification des disponibilités de l'enseignant et des groupes :
        List<String> msg = new ArrayList<String>();
        if(prest.getEnseignant().estIndispo(creneau))
            msg.add("L'enseignant " + prest.getEnseignant() + " n'est pas " +
                    "disponible le " + creneau + ".");
        for(Groupe groupe : prest.getGroupes())
            if(groupe.estIndispo(creneau))
                msg.add("Le groupe '" + groupe + "' n'est pas " +
                         "disponible le " + creneau + ".");

        // puis vérification qu'il n'y a pas de conflit avec d'autres prestations
        List<Groupe> groupes = new ArrayList<Groupe>(prest.getGroupes()); // conversion Collection vers List
        CreneauJpaController ctCreneau = new CreneauJpaController();
        int nbPrest = ctCreneau.countPrestationsPour(creneau, prest.getEnseignant(), groupes);
        if(nbPrest > 0) { // conflit, la prestation ne peut pas être placée dans ce créneau
            // recherche des conflits
            if(prest.getEnseignant().assurePrestationLe(creneau))
                msg.add("L'enseignant " + prest.getEnseignant() + " assure déjà " +
                        "une prestation le " + creneau + ".");
            for(Groupe groupe : prest.getGroupes())
                if(groupe.suitPrestationLe(creneau))
                    msg.add("Le groupe '" + groupe + "' suit déjà " +
                             "une prestation le " + creneau + ".");
        }

        // dernière vérification, les éventuels pools associés au module de la prestation
        // ont-ils encore de la place pour une prestation dans ce créneau
        PoolJpaController ctPool = new PoolJpaController();
        List<Pool> pools = new ArrayList<Pool>(prest.getModule().getPools());
        Map<Pool, Integer> nbPrestRestant = ctPool.getNbPrestRestant(creneau, pools);
        for(Pool pool : pools) {
            Integer nbRestant = nbPrestRestant.get(pool);
            if(nbRestant != null && nbRestant.compareTo(1) < 0)
                msg.add("Le pool '" + pool.getLibelle() + "' est saturé pour ce créneau.");
        }
        return msg; // retourne la liste des conflits
    }

}
